using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;

using System.Diagnostics;

using MossAccess;

namespace MossInvoke
{
    public partial class Form1 : Form
    {
        // The temporary files used for display XML request/response in the browsers
        private string queryRequestFilePath = Path.GetTempPath() + "QueryRequest.XML";
        private string queryResponseFilePath = Path.GetTempPath() + "QueryResponse.XML";

        // The query reques and response
        private QueryRequest queryRequest = new QueryRequest();
        private QueryResponse queryResponse = new QueryResponse();

        // The MOSS query helper object
        private MossQuery mossQuery = new MossQuery();

        /// <summary>
        /// Used to initialise the Windows form
        /// </summary>
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Form closing and clean up
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Delete the temporary files
            DeleteTemporaryXmlFiles();
        }

        /// <summary>
        /// Get search metadata
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonGetSearchMetadata_Click(object sender, EventArgs e)
        {
            // Indicate we're busy doing something
            Cursor.Current = Cursors.WaitCursor;

            GetSearchMetadata();

            // Indicate we're no longer busy doing something
            Cursor.Current = Cursors.Default;
        }

        private void buttonIncludeAllPropertiesInSearch_Click(object sender, EventArgs e)
        {
            SetIncludePropertiesInSearch(true);
        }

        private void buttonIncludeNoSearchProperties_Click(object sender, EventArgs e)
        {
            SetIncludePropertiesInSearch(false);
        }

        private void SetIncludePropertiesInSearch(bool includeSetting)
        {
            foreach (DataGridViewRow propertiesRow in dataGridViewProperties.Rows)
            {
                propertiesRow.Cells["IncludePropertyInResults"].Value = includeSetting;
            }
        }

        /// <summary>
        /// Used to perform the MOSS web service query
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonSearch_Click(object sender, EventArgs e)
        {
            // Indicate we're busy doing something
            Cursor.Current = Cursors.WaitCursor;

            // Indicate we're starting a search
            queryRequest.StartAt = 1;
            queryResponse.TotalAvailable = 1;

            // Build the query request from the user input
            BuildQueryRequest();

            // Perform the query
            PerformQuery();

            // Display the results
            DisplayResults();

            // Indicate we're no longer busy doing something
            Cursor.Current = Cursors.Default;
        }

        /// <summary>
        /// Move backwards in the query result set
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonPrev_Click(object sender, EventArgs e)
        {
            // Indicate we're busy doing something
            Cursor.Current = Cursors.WaitCursor;

            // Build the query request from the user input
            BuildQueryRequest();

            // Decrement the start position
            DecrementSearchStartPosition();

            // Perform the query
            PerformQuery();

            // Display the results
            DisplayResults();

            // Indicate we're no longer busy doing something
            Cursor.Current = Cursors.Default;
        }

        /// <summary>
        /// Move forwards through the result set
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonNext_Click(object sender, EventArgs e)
        {
            // Indicate we're busy doing something
            Cursor.Current = Cursors.WaitCursor;

            // Build the query request from the user input
            BuildQueryRequest();

            // Increment the start position
            IncrementSearchStartPosition();

            // Perform the query
            PerformQuery();

            // Display the results
            DisplayResults();

            // Indicate we're no longer busy doing something
            Cursor.Current = Cursors.Default;
        }

        private void GetSearchMetadata()
        {
            try
            {
                // Get search meta data
                SearchMetadata searchMetadata = mossQuery.GetSearchMetaData();

                dataGridViewProperties.DataSource = searchMetadata.Properties;

                bool retrievable = false;

                foreach (DataGridViewRow propertiesRow in dataGridViewProperties.Rows)
                {
                    retrievable = (bool)propertiesRow.Cells["Retrievable"].Value;
                    propertiesRow.Cells["IncludePropertyInResults"].Value = retrievable;
                    propertiesRow.Cells["Sort"].Value = "None";
                }
            }
            catch (Exception exception)
            {
                // Whoops, something went wrong ...
                MessageBox.Show(exception.ToString(), "Unable to perform query", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Decrement the start position
        /// </summary>
        private void DecrementSearchStartPosition()
        {
            // Set the start position back
            queryRequest.StartAt -= queryRequest.Count;

            // Ensure the start position is sensible
            if (queryRequest.StartAt < 1)
            {
                queryRequest.StartAt = 1;
            }
        }

        /// <summary>
        /// Increment the start position
        /// </summary>
        private void IncrementSearchStartPosition()
        {
            // Set the start position forward
            queryRequest.StartAt += queryRequest.Count;

            // Ensure the start position is sensible
            if (queryRequest.StartAt > queryResponse.TotalAvailable)
            {
                queryRequest.StartAt = queryResponse.TotalAvailable;
            }

        }

        /// <summary>
        /// Build the query request
        /// </summary>
        private void BuildQueryRequest()
        {
            // Set the query text
            queryRequest.QueryText = textBoxQuery.Text;

            // Set the query id
            queryRequest.QueryID = Guid.NewGuid();

            // Decide what type of query we're doing
            if (radioButtonKeyword.Checked)
            {
                queryRequest.QueryType = QueryType.Keyword;
            }
            else
            {
                queryRequest.QueryType = QueryType.MsSql;
            }

            // Set the number of results to return
            queryRequest.Count = Convert.ToInt32(numericUpDownNumberOfResultsToReturn.Value);

            // Set the web service target, if needed
            if (string.IsNullOrEmpty(textBoxTarget.Text) == false)
            {
                queryRequest.Target = textBoxTarget.Text;
            }

            // Set query options, as appropriate
            queryRequest.EnableStemming = checkBoxEnableStemming.Checked;
            queryRequest.IgnoreAllNoiseQuery = checkBoxIgnoreAllNoiseQuery.Checked;
            queryRequest.ImplicitAndBehavior = checkBoxImplicitAndBehavior.Checked;
            queryRequest.TrimDuplicates = checkBoxTrimDuplicates.Checked;
            queryRequest.IncludeRelevantResults = checkBoxIncludeRelevantResults.Checked;
            queryRequest.IncludeHighConfidenceResults = checkBoxIncludeHighConfidenceResults.Checked;
            queryRequest.IncludeSpecialTermResults = checkBoxIncludeSpecialTermResults.Checked;

            // These are some working variables that will be used when adding properties
            string propertyName = string.Empty;
            string sortValue = string.Empty;
            bool includePropertyInResults = true;
            SortDirection sortDirection;
            IncludeInResults includeSortPropertyInResults;
            int sortOrder;

            // Clear out any existing properties
            queryRequest.Properties.Clear();


            if (dataGridViewProperties.Columns.Contains("Name"))
            {

                // Loop through each row in the data grid view
                foreach (DataGridViewRow propertyRow in dataGridViewProperties.Rows)
                {
                    // Get the property name
                    propertyName = (string)propertyRow.Cells["Name"].Value;

                    if (string.IsNullOrEmpty(propertyName) == false)
                    {
                        // Determine whether the property should be included in results
                        includePropertyInResults = (bool)propertyRow.Cells["IncludePropertyInResults"].Value;

                        // Determine the sort direction
                        sortValue = (string)propertyRow.Cells["Sort"].Value;

                        // If the sort direction is NONE, just add the property
                        if (string.Equals(sortValue, "None", StringComparison.InvariantCultureIgnoreCase) == true)
                        {
                            // If the property should be included in the results
                            if (includePropertyInResults)
                            {
                                // Add it to the query result
                                queryRequest.AddProperty(propertyName);
                            }
                        }
                        else // Otherwise, we need to determine the sort direction and priority
                        {
                            // Determine whether the sort property should also be included in the results
                            includeSortPropertyInResults = includePropertyInResults ? IncludeInResults.Yes : IncludeInResults.No;

                            // Parse the sort value from the data grid and use it to seed a SortDirection enum
                            sortDirection = (SortDirection)Enum.Parse(typeof(SortDirection), sortValue, true);

                            // Get the sort order value
                            if (Int32.TryParse((string)propertyRow.Cells["SortOrder"].Value, out sortOrder) == false)
                            {
                                sortOrder = 0;
                            }

                            // Add the property to the query request and specify whether it should be included in the results, the sort order and priority
                            queryRequest.AddProperty(propertyName, includeSortPropertyInResults, sortDirection, sortOrder);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Perform the query
        /// </summary>
        private void PerformQuery()
        {
            try
            {
                // Perform the query
                queryResponse = mossQuery.PerformQuery(queryRequest);
            }
            catch (Exception exception)
            {
                // Whoops, something went wrong ...
                MessageBox.Show(exception.ToString(), "Unable to perform query", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Display the results
        /// </summary>
        private void DisplayResults()
        {
            // Set the status strip labels
            statusStrip.Items["toolStripStatusLabelStartAt"].Text = "Start at: " + queryResponse.StartAt.ToString();
            statusStrip.Items["toolStripStatusLabelCount"].Text = "Count: " + queryResponse.Count.ToString();
            statusStrip.Items["toolStripStatusLabelTotalAvailable"].Text = "Total available: " + queryResponse.TotalAvailable.ToString();


            // Display the request XML document, if there was once
            if (string.IsNullOrEmpty(queryResponse.XmlQueryRequest) == false)
            {
                // Write the text out to a file
                WriteFile(queryRequestFilePath, queryResponse.XmlQueryRequest);

                // Navigate to the file
                webBrowserQueryRequest.Navigate(queryRequestFilePath);
            }
            else
            {
                // Display the BLANK page
                webBrowserQueryRequest.Navigate("about:blank");
            }

            // Display the response XML document, if there was one
            if (string.IsNullOrEmpty(queryResponse.XmlQueryResponse) == false)
            {
                // Write the text out to a file
                WriteFile(queryResponseFilePath, queryResponse.XmlQueryResponse);

                // Navigate to the file
                webBrowserQueryResponse.Navigate(queryResponseFilePath);
            }
            else
            {
                // Display the BLANK page
                webBrowserQueryResponse.Navigate("about:blank");
            }
           
            // Display the data table responses
            dataGridViewRelevantResults.DataSource = queryResponse.DataTableQueryRelevantResults;
            dataGridViewHighConfidenceResults.DataSource = queryResponse.DataTableQueryHighConfidenceResults;
            dataGridViewSpecialTermResults.DataSource = queryResponse.DataTableQuerySpecialTermResults;

            // Enable/Disable "previous" button, as appropriate
            if (queryRequest.StartAt <= 1)
            {
                buttonPrev.Enabled = false;
            }
            else
            {
                buttonPrev.Enabled = true;
            }

            // Enable/Disable "next" button, as appropriate
            if (queryRequest.StartAt + queryRequest.Count < queryResponse.TotalAvailable)
            {
                buttonNext.Enabled = true;
            }
            else
            {
                buttonNext.Enabled = false;
            }

        }

        /// <summary>
        /// Write a string to a file
        /// </summary>
        /// <param name="fileName">The name of the file</param>
        /// <param name="fileContents">The string to write out</param>
        private void WriteFile(string fileName, string fileContents)
        {
            // Create the file
            FileStream fileStream = File.Create(fileName);

            // Get the bytes to write out
            byte[] fileContentBytes = UTF8Encoding.Default.GetBytes(fileContents);


            // Write the bytes
            fileStream.Write(fileContentBytes, 0, fileContentBytes.Length);

            // Flush the bytes to the file
            fileStream.Flush();

            // Close the file
            fileStream.Close();
        }

        /// <summary>
        /// Delete the temporary files
        /// </summary>
        private void DeleteTemporaryXmlFiles()
        {
            if ( Directory.Exists(queryRequestFilePath))
            {
                Directory.Delete(queryRequestFilePath);
            }
            if (Directory.Exists(queryResponseFilePath))
            {
                Directory.Delete(queryResponseFilePath);
            }
        }
    }
}